//
//  Created by Patrick Hogan on 10/12/12.
//


////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Public Interface
////////////////////////////////////////////////////////////////////////////////////////////////////////////
#import "BDAESCryptor.h"

////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Utilities
////////////////////////////////////////////////////////////////////////////////////////////////////////////
#import "NSObject+BDJSONSerialization.h"
#import <CommonCrypto/CommonKeyDerivation.h>


////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Constants
////////////////////////////////////////////////////////////////////////////////////////////////////////////
const uint32_t AESKeySize      =    32;
const uint32_t AESIVSize       =    16;
const uint32_t AESSaltSize     =     8;
const uint32_t PBKDF2IterCount = 10000;


////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Implementation
////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation BDAESCryptor


////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Convenience
////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSInteger)maximumBlockSize
{
    return 65535;
}


- (NSInteger)keySize
{
    return 0;
}


- (BOOL)serializedObjectSatisfiesLengthConstraint:(NSObject *)object
                                            error:(BDError *)error
{
    return [self stringSatisfiesLengthConstraint:[object stringValue:error]
                                           error:error];
}


- (BOOL)stringSatisfiesLengthConstraint:(NSObject *)object
                                  error:(BDError *)error
{
    if ([[object stringValue:error] length] < [self maximumBlockSize])
    {
        return YES;
    }
    
    return NO;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Password based key derivation
////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSData *)PBKDF2WithKey:(NSString *)key
                     salt:(NSData *)saltDataObject
{
    NSMutableData *derivedKey = [NSMutableData dataWithLength:AESKeySize];
    
    CCKeyDerivationPBKDF(kCCPBKDF2,
                         (const char *)[key dataUsingEncoding:NSUTF8StringEncoding].bytes,
                         key.length,
                         (const uint8_t *)saltDataObject.bytes,
                         saltDataObject.length,
                         kCCPRFHmacAlgSHA256,
                         PBKDF2IterCount,
                         (uint8_t *)[derivedKey mutableBytes],
                         derivedKey.length);
    
    return derivedKey;
}


@end
